<template>
    <div class="page">
        <h2 class="title">通用合同管理</h2>

        <!-- 搜索区（提交式） -->
        <div class="search">
            <div class="row">
                <label>合同标题：</label>
                <input v-model="inputFilters.contractTitle" placeholder="请输入合同标题" @keyup.enter="handleSearch" />

                <label>对方单位：</label>
                <input v-model="inputFilters.counterpartyUnit" placeholder="请输入对方单位" @keyup.enter="handleSearch" />

                <label>对方负责人：</label>
                <input v-model="inputFilters.counterpartyContact" placeholder="请输入对方负责人" @keyup.enter="handleSearch" />
            </div>
            <div class="row">
                <label>经办人：</label>
                <input v-model="inputFilters.handler" placeholder="请输入经办人" @keyup.enter="handleSearch" />

                <label>签订时间：</label>
                <input type="date" v-model="inputFilters.signingStart" @keyup.enter="handleSearch" />
                <span> - </span>
                <input type="date" v-model="inputFilters.signingEnd" @keyup.enter="handleSearch" />

                <label>审批状态：</label>
                <select v-model="inputFilters.status">
                    <option value="">全部</option>
                    <option value="0">待提交</option>
                    <option value="1">待审批</option>
                    <option value="2">已通过</option>
                    <option value="3">已拒绝</option>
                </select>

                <button class="btn primary" @click="handleSearch">查询</button>
                <button class="btn" @click="handleReset">重置</button>
            </div>
        </div>

        <div class="toolbar">
            <button class="btn primary" @click="handleCreate">新增</button>
            <button class="btn danger" :disabled="selectedIds.length === 0" @click="handleBatchDelete">删除</button>
        </div>

        <!-- 表格 -->
        <div class="table-wrapper">
            <table class="table">
                <thead>
                    <tr>
                        <th style="width: 36px"><input type="checkbox" :checked="allSelected" @change="toggleAll" />
                        </th>
                        <th>合同编号</th>
                        <th>合同标题</th>
                        <th>对方单位</th>
                        <th>对方联系人</th>
                        <th>合同类型</th>
                        <th>签订日期</th>
                        <th>经办人</th>
                        <th>创建时间</th>
                        <th>状态</th>
                        <th>审批人</th>
                        <th>操作</th>
                    </tr>
                </thead>
                <tbody>
                    <tr v-if="loading">
                        <td :colspan="12" style="text-align:center">加载中...</td>
                    </tr>
                    <tr v-else-if="rows.length === 0">
                        <td :colspan="12" style="text-align:center">暂无数据</td>
                    </tr>
                    <tr v-for="row in rows" :key="row.id">
                        <td><input type="checkbox" :checked="selectedIds.includes(row.id)"
                                @change="toggleOne(row.id)" /></td>
                        <td>{{ row.contractNumber || '-' }}</td>
                        <td>{{ row.contractTitle || '-' }}</td>
                        <td>{{ row.counterpartyUnit || '-' }}</td>
                        <td>{{ row.counterpartyContact || '-' }}</td>
                        <td>{{ row.contractType || '-' }}</td>
                        <td>{{ row.signingDate }}</td>
                        <td>{{ row.handler || '-' }}</td>
                        <td>{{ row.createdAt }}</td>
                        <td>{{ row.status || '-' }}</td>
                        <td>{{ row.approver || '-' }}</td>
                        <td>
                            <a href="javascript:void(0)" @click="handleEdit(row)">编辑</a>
                            &nbsp;|&nbsp;
                            <a href="javascript:void(0)" class="danger" @click="handleDelete(row)">删除</a>
                            &nbsp;|&nbsp;
                            <a href="javascript:void(0)" @click="handleView(row)">查看</a>
                            &nbsp;|&nbsp;
                            <a href="javascript:void(0)" @click="handleSubmitApproval(row)">提交审批</a>
                        </td>
                    </tr>
                </tbody>
            </table>
        </div>

        <!-- 分页（数字页码 + 跳转） -->
        <div class="pagination advanced" v-if="total > 0">
            <span class="sum">共{{ totalPage }}页/{{ total }}条数据</span>
            <button class="nav" :disabled="page === 1" @click="goto(page - 1)">‹</button>
            <button v-for="p in pagesToShow" :key="p.key" class="num"
                :class="{ active: p.page === page, ellipsis: p.ellipsis }" :disabled="p.ellipsis"
                @click="!p.ellipsis && goto(p.page)">
                {{ p.label }}
            </button>
            <button class="nav" :disabled="page >= totalPage" @click="goto(page + 1)">›</button>
            <span class="jump">跳至</span>
            <input class="jump-input" type="number" min="1" :max="Math.max(totalPage, 1)" v-model.number="jumpPage"
                @keyup.enter="jump()" />
            <span class="jump">页</span>
        </div>

        <!-- 详情弹窗 -->
        <div class="dialog-mask" v-if="showDetail" @click.self="closeDetail">
            <div class="dialog">
                <h3>合同详情</h3>
                <div v-if="detailLoading">加载中...</div>
                <div v-else>
                    <p><b>合同编号：</b>{{ detail.contractNumber || '-' }}</p>
                    <p><b>合同标题：</b>{{ detail.contractTitle || '-' }}</p>
                    <p><b>对方单位：</b>{{ detail.counterpartyUnit || '-' }}</p>
                    <p><b>对方联系人：</b>{{ detail.counterpartyContact || '-' }}</p>
                    <p><b>合同类型：</b>{{ detail.contractType || '-' }}</p>
                    <p><b>签订日期：</b>{{ detail.signingDate }}</p>
                    <p><b>经办人：</b>{{ detail.handler || '-' }}</p>
                    <p><b>创建时间：</b>{{ detail.createdAt }}</p>
                    <p><b>状态：</b>{{ detail.status || '-' }}</p>
                    <p><b>审批人：</b>{{ detail.approver || '-' }}</p>
                    <p v-if="detail.contractSubjectDescription"><b>合同标的/项目说明：</b><br />{{
                        detail.contractSubjectDescription }}</p>
                    <p v-if="detail.contractTerms"><b>主要条款/变更条款：</b><br />{{ detail.contractTerms }}</p>
                    <p v-if="detail.attachments && detail.attachments.length"><b>附件：</b>
                        <span v-for="(a, i) in detail.attachments" :key="i">
                            <a :href="a" target="_blank">{{ getFileName(a) }}</a><span
                                v-if="i < detail.attachments.length - 1">, </span>
                        </span>
                    </p>
                </div>
                <div class="dialog-footer">
                    <button class="btn" @click="closeDetail">关闭</button>
                </div>
            </div>
        </div>
    </div>
</template>

<script setup lang="ts">
import { ref, reactive, onMounted, computed } from 'vue'
import { useRouter } from 'vue-router'
import { useCounterStore } from '@/stores/counter'
import { read, write } from '@/assets/Axios/axiosHttple'

const router = useRouter()
const counts = useCounterStore()

// 提交式查询输入与实际查询条件
const inputFilters = reactive({
    contractTitle: '',
    counterpartyUnit: '',
    counterpartyContact: '',
    handler: '',
    signingStart: '',
    signingEnd: '',
    status: ''
})
const filters = reactive({
    contractTitle: '',
    counterpartyUnit: '',
    counterpartyContact: '',
    handler: '',
    signingStart: '',
    signingEnd: '',
    status: ''
})

const page = ref(1)
const pageSize = ref(10)
const total = ref(0)
const totalPage = ref(0)
const loading = ref(false)
const rows = ref<any[]>([])
const jumpPage = ref<number | null>(1)

const selectedIds = ref<number[]>([])
const allSelected = ref(false)

function toggleOne(id: number) {
    if (selectedIds.value.includes(id)) {
        selectedIds.value = selectedIds.value.filter(x => x !== id)
    } else {
        selectedIds.value.push(id)
    }
    allSelected.value = rows.value.length > 0 && selectedIds.value.length === rows.value.length
}
function toggleAll(e: Event) {
    const checked = (e.target as HTMLInputElement).checked
    allSelected.value = checked
    selectedIds.value = checked ? rows.value.map(r => r.id) : []
}

function handleCreate() {
    router.push('/AddGeneralContracts')
}

async function handleDelete(row: any) {
    if (!row || !row.id) {
        alert('缺少要删除的记录ID')
        return
    }
    if (!confirm('确定要删除该通用合同吗？此操作不可撤销。')) return

    try {
        const id = Number(row.id)
        const payload = {
            command: 'delete',
            deletedBy: String(counts.Logins.UserId ?? counts.Logins.Account ?? ''),
            deletedByName: String(counts.Logins.Nickname ?? counts.Logins.Account ?? ''),
            createdBy: String(counts.Logins.UserId ?? counts.Logins.Account ?? counts.Logins.Nickname ?? ''),
            id
        }
        const candidates = [
            `contractmanagementwrite/api/ContractManagement/DeleteGeneral/general/delete/${encodeURIComponent(String(id))}`,
            `contractmanagementwrite/api/ContractManagement/Delete/delete/${encodeURIComponent(String(id))}`,
            'contractmanagementwrite/api/ContractManagement/DeleteGeneral/general/delete',
            'contractmanagementwrite/api/ContractManagement/Delete/delete'
        ]
        let lastErr: any = null
        for (const u of candidates) {
            try {
                const res = await write.post(u, payload)
                const d = res?.data ?? {}
                if (res.status === 200 && (Number(d?.code) === 200 || d?.data === true)) {
                    alert('删除成功')
                    fetchList()
                    return
                }
                lastErr = { status: res?.status, body: d }
            } catch (e) { lastErr = e }
        }
        console.error('[handleDelete] last error', lastErr)
        alert(lastErr?.body?.message || lastErr?.message || '删除失败')
    } catch (e) {
        console.error(e)
        alert('删除失败，请重试')
    }
}

async function handleBatchDelete() {
    if (selectedIds.value.length === 0) { alert('请选择要删除的记录'); return }
    if (!confirm(`确定删除 ${selectedIds.value.length} 条记录？此操作不可撤销。`)) return
    try {
        const body = {
            ids: selectedIds.value,
            command: 'delete',
            deletedBy: String(counts.Logins.UserId ?? counts.Logins.Account ?? ''),
            deletedByName: String(counts.Logins.Nickname ?? counts.Logins.Account ?? '')
        }
        const candidates = [
            'contractmanagementwrite/api/ContractManagement/DeleteRangeGeneral/general/delete/batch',
            'contractmanagementwrite/api/ContractManagement/DeleteRange/delete/batch'
        ]
        let lastErr: any = null
        for (const u of candidates) {
            try {
                const res = await write.post(u, body)
                const d = res?.data ?? {}
                if (res.status === 200 && (Number(d?.code) === 200 || d?.data === true)) {
                    alert('批量删除成功')
                    selectedIds.value = []
                    fetchList()
                    return
                }
                lastErr = { status: res?.status, body: d }
            } catch (e) { lastErr = e }
        }
        console.error('[handleBatchDelete] last error', lastErr)
        alert(lastErr?.body?.message || lastErr?.message || '批量删除失败')
    } catch (e) {
        console.error(e)
        alert('批量删除失败，请重试')
    }
}

function handleEdit(row: any) {
    router.push(`/UpdateGeneralContracts?id=${encodeURIComponent(row.id)}`)
}

const showDetail = ref(false)
const detailLoading = ref(false)
const detail = ref<any>({})

function closeDetail() { showDetail.value = false }

async function handleView(row: any) {
    showDetail.value = true
    detailLoading.value = true
    try {
        detail.value = { ...row }
    } finally {
        detailLoading.value = false
    }
}

// 提交审批：本地直接成功并更新状态与审批人
async function handleSubmitApproval(row: any) {
    if (!row) { alert('缺少记录ID，无法提交审批'); return }
    try {
        row.status = '待审核'
        row.approver = '王总'
        const idx = rows.value.findIndex(r => r.id === row.id)
        if (idx >= 0) rows.value[idx] = { ...rows.value[idx], status: row.status, approver: row.approver }
    } finally {
        alert('提交成功')
    }
}

function handleSearch() {
    filters.contractTitle = inputFilters.contractTitle.trim()
    filters.counterpartyUnit = inputFilters.counterpartyUnit.trim()
    filters.handler = inputFilters.handler.trim()
    filters.signingStart = inputFilters.signingStart
    filters.signingEnd = inputFilters.signingEnd
    filters.status = inputFilters.status
    page.value = 1
    fetchList()
}

function handleReset() {
    inputFilters.contractTitle = ''
    inputFilters.counterpartyUnit = ''
    inputFilters.handler = ''
    inputFilters.signingStart = ''
    inputFilters.signingEnd = ''
    inputFilters.status = ''
    filters.contractTitle = ''
    filters.counterpartyUnit = ''
    filters.handler = ''
    filters.signingStart = ''
    filters.signingEnd = ''
    filters.status = ''
    page.value = 1
    fetchList()
}

function goto(p: number) {
    if (p < 1 || (totalPage.value && p > totalPage.value)) return
    page.value = p
    fetchList()
}

function jump() {
    if (!jumpPage.value) return
    const p = Math.max(1, Math.min(Number(jumpPage.value), Math.max(totalPage.value, 1)))
    goto(p)
}

const pagesToShow = computed(() => {
    const maxPage = Math.max(totalPage.value, 1)
    const current = Math.min(Math.max(page.value, 1), maxPage)
    const pages: { key: string; page: number; label: string; ellipsis?: boolean }[] = []
    const pushPage = (p: number) => pages.push({ key: `p-${p}`, page: p, label: String(p) })
    const pushEllipsis = (i: number) => pages.push({ key: `e-${i}`, page: -1, label: '...', ellipsis: true })

    if (maxPage <= 7) {
        for (let i = 1; i <= maxPage; i++) pushPage(i)
        return pages
    }
    pushPage(1)
    if (current > 4) pushEllipsis(1)
    const start = Math.max(2, current - 1)
    const end = Math.min(maxPage - 1, current + 1)
    for (let i = start; i <= end; i++) pushPage(i)
    if (current < maxPage - 3) pushEllipsis(2)
    pushPage(maxPage)
    return pages
})

// 从 URL 或 fileName 中提取文件名
function getFileName(url: string) {
    try {
        const u = new URL(url)
        const p = u.pathname || ''
        const segs = p.split('/')
        const last = segs[segs.length - 1] || url
        return decodeURIComponent(last)
    } catch {
        const segs = String(url).split(/[\\/]/)
        return segs[segs.length - 1] || String(url)
    }
}

function normalizeDateString(val: any) {
    if (!val) return ''
    try {
        const d = new Date(val)
        if (isNaN(d.getTime())) return ''
        return d.toISOString().slice(0, 10)
    } catch { return '' }
}

// 宽松字段取值：支持大小写不敏感匹配和多个备选字段名
function pickField(obj: any, ...names: string[]) {
    if (!obj) return undefined
    for (const name of names) {
        if (Object.prototype.hasOwnProperty.call(obj, name) && obj[name] != null) return obj[name]
    }
    const keyMap: Record<string, string> = {}
    Object.keys(obj || {}).forEach(k => { keyMap[k.toLowerCase()] = k })
    for (const name of names) {
        const k = keyMap[name.toLowerCase()]
        if (k && obj[k] != null) return obj[k]
    }
    return undefined
}

// 提取对方单位与联系人：支持扁平字段和嵌套对象，覆盖多种命名习惯
function extractCounterparty(item: any) {
    if (!item) return { unit: undefined, contact: undefined }
    // 先尝试常见扁平字段
    const unit = pickField(item,
        'CounterpartyUnit', 'counterpartyUnit', 'CounterpartyUnitName', 'counterparty_unit', 'counterparty',
        'OppositeUnit', 'OppositeUnitName', 'UnitName', 'unitName', 'CompanyName', 'companyName', 'Unit')

    const contact = pickField(item,
        'CounterpartyContact', 'counterpartyContact', 'Contact', 'contact', 'ContactName', 'contactName',
        'LinkMan', 'LinkPerson', 'Principal', 'principal', 'OwnerName', 'ownerName')

    if ((unit && unit !== '') || (contact && contact !== '')) return { unit, contact }

    // 再尝试嵌套对象，例如 item.Counterparty = { name, contact }
    const nestedKeys = ['Counterparty', 'counterparty', 'Party', 'party', 'Partner', 'partner', 'Company', 'company']
    for (const k of nestedKeys) {
        const sub = item[k]
        if (!sub || typeof sub !== 'object') continue
        const subUnit = pickField(sub, 'UnitName', 'unitName', 'Name', 'name', 'CompanyName', 'companyName')
        const subContact = pickField(sub, 'Contact', 'contact', 'ContactName', 'contactName', 'LinkMan', 'linkMan')
        if (subUnit || subContact) return { unit: subUnit, contact: subContact }
    }

    // 进一步尝试：有时对方信息在 item.CounterpartyInfo 或 item.Opponent
    const altKeys = ['CounterpartyInfo', 'counterpartyInfo', 'Opponent', 'opponent', 'Opposite']
    for (const k of altKeys) {
        const sub = item[k]
        if (!sub || typeof sub !== 'object') continue
        const subUnit = pickField(sub, 'UnitName', 'unitName', 'Name', 'name')
        const subContact = pickField(sub, 'Contact', 'contact', 'ContactName', 'contactName')
        if (subUnit || subContact) return { unit: subUnit, contact: subContact }
    }

    return { unit: undefined, contact: undefined }
}

async function fetchList() {
    loading.value = true
    try {
        const params = new URLSearchParams()
        params.append('PageIndex', String(page.value))
        params.append('PageSize', String(pageSize.value))
        if (filters.contractTitle) {
            params.append('contractTitle', filters.contractTitle); params.append('ContractTitle', filters.contractTitle)
        }
        if (filters.counterpartyUnit) {
            // 支持多种后端参数命名：counterpartyUnit / unitName / partnerUnit / CounterpartyUnitName
            params.append('counterpartyUnit', filters.counterpartyUnit)
            params.append('CounterpartyUnit', filters.counterpartyUnit)
            params.append('CounterpartyUnitName', filters.counterpartyUnit)
            params.append('unitName', filters.counterpartyUnit)
            params.append('UnitName', filters.counterpartyUnit)
            params.append('partnerUnit', filters.counterpartyUnit)
            params.append('PartnerUnit', filters.counterpartyUnit)
        }
        // 支持按对方联系人查询
        if (filters.counterpartyContact) {
            params.append('counterpartyContact', filters.counterpartyContact)
            params.append('CounterpartyContact', filters.counterpartyContact)
        }
        if (filters.handler) { params.append('handler', filters.handler); params.append('Handler', filters.handler) }
        if (filters.status) {
            // 支持状态多种命名，部分接口可能用 processDetail（数字）或 approvalStatus
            // 如果用户传入的是数字字符串，直接使用
            const maybeNum = Number(filters.status)
            if (!Number.isNaN(maybeNum)) {
                params.append('ApprovalStatus', String(maybeNum))
                params.append('approvalStatus', String(maybeNum))
                params.append('status', String(maybeNum))
            } else {
                // 文本映射到后端枚举（根据后端说明：0 待提交,1 待审批,2 已通过,3 已拒绝）
                const map: Record<string, number> = {
                    '待提交': 0,
                    '待审批': 1,
                    '已通过': 2,
                    '已审核': 2,
                    '已拒绝': 3
                }
                const v = map[filters.status] ?? map[filters.status.trim()] ?? -1
                if (v >= 0) {
                    params.append('ApprovalStatus', String(v))
                    params.append('approvalStatus', String(v))
                    params.append('status', String(v))
                    params.append('ProcessDetail', String(v))
                } else {
                    params.append('status', filters.status)
                    params.append('Status', filters.status)
                }
            }
        }
        // 签订时间：若选择范围则传 startDate/endDate；若只选单日，则传 SigningDate
        if (filters.signingStart && filters.signingEnd) {
            params.append('startDate', filters.signingStart)
            params.append('endDate', filters.signingEnd)
        } else if (filters.signingStart) {
            params.append('SigningDate', filters.signingStart)
        } else if (filters.signingEnd) {
            params.append('SigningDate', filters.signingEnd)
        }
        params.append('t', String(Date.now()))

        const url = `contractmanagementread/api/ContractManagementControllers/GetGeneralContracts/General`
        const res = await read.get(url, { params })
        const json: any = res?.data ?? {}

        const container = json?.data || {}
        total.value = Number(container?.TotalCount || 0)
        totalPage.value = Number(container?.TotalPage || 0)
        const list = Array.isArray(container?.data) ? container.data : []

        // 预加载单位列表（External），用于当接口只返回单位ID时映射显示单位名称
        let unitMap: Record<number, string> = {}
        try {
            const ures = await read.get('baseinforead/api/External/GetExternalList', { params: { PageIndex: 1, PageSize: 999 } })
            if (ures?.status === 200) {
                const uj: any = ures.data ?? {}
                const ublock = uj?.data || uj
                const ulist = Array.isArray(ublock) ? ublock : (Array.isArray(ublock?.data) ? ublock.data : [])
                ulist.forEach((x: any) => {
                    const id = Number(x.Id ?? x.id ?? x.UnitId ?? x.unitId)
                    const name = x.UnitName ?? x.unitName ?? x.Name ?? x.name ?? x.CompanyName ?? x.companyName
                    if (Number.isFinite(id) && name) unitMap[id] = name
                })
            }
        } catch (e) { /* ignore unit preload errors */ }
        rows.value = list.map((it: any) => {
            const cp = extractCounterparty(it)
            return {
                id: pickField(it, 'Id', 'id') ?? pickField(it, 'ID') ?? null,
                contractNumber: (pickField(it, 'ContractNumber', 'contractNumber', 'ContractNo', 'contractNo') ?? '') as string,
                contractTitle: (pickField(it, 'ContractTitle', 'contractTitle', 'Title', 'title') ?? '') as string,
                // 初步尝试从记录中提取对方单位/联系人
                // 优先使用 extractCounterparty 提取的单位名；如果没有但记录包含单位ID，则用预加载的 unitMap 映射名称
                counterpartyUnit: (cp.unit ?? pickField(it, 'CounterpartyUnit', 'counterpartyUnit', 'CounterpartyUnitName', 'counterparty') ?? ((): string | undefined => {
                    const uid = pickField(it, 'CounterpartyUnitId', 'counterpartyUnitId', 'UnitId', 'unitId', 'unit')
                    const n = Number(uid)
                    if (!Number.isNaN(n) && unitMap[n]) return unitMap[n]
                    return undefined
                })() ?? '') as string,
                counterpartyContact: (cp.contact ?? pickField(it, 'CounterpartyContact', 'counterpartyContact', 'Contact', 'contact') ?? '') as string,
                // 记录可能包含货主ID，用于后续向货主管理接口查询补全信息
                cargoOwnerId: pickField(it, 'CargoOwnerId', 'cargoOwnerID', 'cargoownerid', 'OwnerId', 'ownerId') ?? null,
                contractType: (pickField(it, 'ContractType', 'contractType', 'contractCategory') ?? '') as string,
                signingDate: normalizeDateString(pickField(it, 'SigningDate', 'signingDate', 'signDate')),
                handler: (pickField(it, 'Handler', 'handler', 'CreatedBy', 'createdBy') ?? '') as string,
                createdAt: normalizeDateString(pickField(it, 'CreatedAt', 'createdAt', 'CreateDate', 'createDate')),
                status: (pickField(it, 'Status', 'status') ?? '') as string,
                approver: (pickField(it, 'Approver', 'approver', 'ApprovedBy', 'approvedBy') ?? '') as string,
                // 附件字段兼容：优先 contractAttachments 数组，否则尝试解析 contractAttachment/fileUrl/filePath
                attachments: Array.isArray(it.contractAttachments) ? it.contractAttachments : (it.contractAttachments ? String(it.contractAttachments).split(',') : (it.contractAttachment ? String(it.contractAttachment).split(',') : (it.fileUrl ? [it.fileUrl] : (it.filePath ? [it.filePath] : []))))
            }
        })

        // 如果列表中存在没有对方单位但带有货主ID的记录，批量查询货主管理接口补全显示
        try {
            const ids = Array.from(new Set(rows.value.filter((r: any) => (!r.counterpartyUnit || r.counterpartyUnit === '') && r.cargoOwnerId).map((r: any) => Number(r.cargoOwnerId)).filter(n => !Number.isNaN(n))))
            if (ids.length > 0) {
                const infoMap: Record<number, { unit?: string; contact?: string }> = {}
                await Promise.all(ids.map(async id => {
                    try {
                        const res = await read.get(`baseinforead/api/CargoOwner/GetCargoOwnerById/${encodeURIComponent(String(id))}`)
                        if (res?.status !== 200) return
                        const d = res.data?.data ?? res.data
                        if (d) {
                            const unit = d.UnitName ?? d.unitName ?? d.CompanyName ?? d.companyName ?? d.Name ?? d.name
                            const contact = d.OwnerName ?? d.ownerName ?? d.Contact ?? d.contact ?? d.Principal ?? d.principal
                            infoMap[id] = { unit: unit || undefined, contact: contact || undefined }
                        }
                    } catch (err) {
                        // ignore per-id fetch errors
                    }
                }))

                // 应用补全结果到 rows
                rows.value = rows.value.map((r: any) => {
                    const cid = Number(r.cargoOwnerId)
                    if (cid && infoMap[cid]) {
                        return {
                            ...r,
                            counterpartyUnit: r.counterpartyUnit || infoMap[cid].unit || '',
                            counterpartyContact: r.counterpartyContact || infoMap[cid].contact || ''
                        }
                    }
                    return r
                })
            }
        } catch (err) {
            console.error('[fetchList] cargoOwner补全失败', err)
        }
    } catch (e) {
        console.error(e)
        rows.value = []
        total.value = 0
        totalPage.value = 0
    } finally {
        loading.value = false
    }
}

onMounted(() => {
    const url = new URL(window.location.href)
    if (url.searchParams.get('refresh') === '1') {
        url.searchParams.delete('refresh')
        history.replaceState(null, '', `${url.pathname}${url.search}`)
    }
    fetchList()
})
</script>

<style scoped>
.page {
    padding: 16px;
}

.title {
    margin: 8px 0 12px;
    font-size: 18px;
}

.search {
    background: #f7f7f7;
    padding: 12px;
    border-radius: 6px;
    margin-bottom: 12px;
}

.row {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 8px;
    flex-wrap: wrap;
}

.row label {
    color: #333;
}

input,
select {
    height: 30px;
    padding: 0 8px;
    border: 1px solid #ddd;
    border-radius: 4px;
}

.btn {
    height: 30px;
    padding: 0 12px;
    border: 1px solid #ddd;
    background: #fff;
    border-radius: 4px;
    cursor: pointer;
}

.btn.primary {
    background: #1677ff;
    color: #fff;
    border-color: #1677ff;
}

.btn.danger {
    background: #ff4d4f;
    color: #fff;
    border-color: #ff4d4f;
}

.toolbar {
    display: flex;
    gap: 8px;
    margin: 8px 0;
}

.table {
    width: 100%;
    border-collapse: collapse;
    background: #fff;
}

.table th,
.table td {
    border: 1px solid #eee;
    padding: 8px;
    text-align: left;
}

.table thead {
    background: #fafafa;
}

.table a {
    color: #1677ff;
    text-decoration: none;
}

.table a.danger {
    color: #ff4d4f;
}

.table-wrapper {
    overflow: auto;
}

.pagination {
    display: flex;
    gap: 12px;
    align-items: center;
    justify-content: center;
    padding: 12px 0;
}

.pagination.advanced {
    gap: 6px;
}

.pagination .num {
    min-width: 32px;
    height: 28px;
    border: 1px solid #ddd;
    background: #fff;
    border-radius: 4px;
    cursor: pointer;
}

.pagination .num.active {
    background: #13c2c2;
    color: #fff;
    border-color: #13c2c2;
}

.pagination .num.ellipsis {
    cursor: default;
    padding: 0 8px;
}

.pagination .nav {
    min-width: 32px;
    height: 28px;
    border: 1px solid #ddd;
    background: #fff;
    border-radius: 4px;
    cursor: pointer;
}

.pagination .sum {
    color: #666;
    margin-right: 6px;
}

.pagination .jump {
    color: #666;
}

.pagination .jump-input {
    width: 56px;
    height: 28px;
    padding: 0 6px;
    border: 1px solid #ddd;
    border-radius: 4px;
}

.dialog-mask {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.35);
    display: flex;
    align-items: center;
    justify-content: center;
}

.dialog {
    width: 520px;
    max-width: 90vw;
    background: #fff;
    border-radius: 8px;
    padding: 16px;
}

.dialog-footer {
    display: flex;
    justify-content: flex-end;
    margin-top: 12px;
}
</style>
